<?php

namespace App\Models\BackHome\AuthManage;

use Illuminate\Support\Facades\DB;

/**
 * 菜单管理
 * Class MenuModel
 * @package app\back\model
 */
class MenuModel
{
    /**
     * 创建菜单
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function addMenu($data)
    {
        $nowTime = time();
        $insertData = [
            'menu_type' => 1,
            'parent_id' => $data['parentId'],
            'name' => $data['name'],
            'description' => isset($data['description']) ? $data['description'] : "",
            'key_val' => isset($data['keyVal']) ? $data['keyVal'] : "",
            'url' => isset($data['url']) ? $data['url'] : "",
            'icon' => isset($data['icon']) ? $data['icon'] : "",
            'include_str' => isset($data['includeStr']) ? $data['includeStr'] : "",
            'sort' => isset($data['sort']) ? (int)$data['sort'] : 0,
            'create_time' => $nowTime,
            'update_time' => $nowTime,
            'status' => 1,
            'depth' => '|'
        ];

        if ($data['parentId'] > 0) {
            $isExits = DB::table('sc_system_menu')->where('id', $data['parentId'])->select(['id', 'depth'])->first();
            if (!$isExits) {
                return ModelReturn(1, '父级菜单不存在');
            }

            $insertData['depth'] = $isExits->depth;
        }

        $iCnt = DB::table('sc_system_menu')->insertGetId($insertData);
        if ($iCnt) {
            DB::table('sc_system_menu')->where('id', $iCnt)->update([
                'depth' => '|' . $iCnt . $insertData['depth']
            ]);
            HandleLog()->addLog('i', $data, '创建了菜单:' . $data['name']);
            return ModelReturn(RETURN_SUCCESS, '创建成功', ['menuId' => $iCnt]);
        } else {
            return ModelReturn(RETURN_FAIL, '创建失败');
        }
    }

    /**
     * 编辑菜单
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function editMenu($data)
    {
        if ($data['parentId'] == $data['id']) {
            return ModelReturn(RETURN_FAIL, '修改的父级ID不能与自身ID一致');
        }

        $nowTime = time();
        $updateData = [
            'parent_id' => $data['parentId'],
            'name' => $data['name'],
            'description' => isset($data['description']) ? $data['description'] : "",
            'key_val' => isset($data['keyVal']) ? $data['keyVal'] : "",
            'url' => isset($data['url']) ? $data['url'] : "",
            'icon' => isset($data['icon']) ? $data['icon'] : "",
            'include_str' => isset($data['includeStr']) ? $data['includeStr'] : "",
            'sort' => isset($data['sort']) ? (int)$data['sort'] : 0,
            'update_time' => $nowTime
        ];

        $id = $data['id'];
        if ($data['parentId'] > 0) {
            $parentObj = DB::table('sc_system_menu')->where('id', $data['parentId'])->select(['id', 'depth'])->first();
            if (!$parentObj) {
                return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '父级菜单不存在');
            }
        }

        $menuObj = DB::table('sc_system_menu')->where('id', $id)->select(['id', 'name', 'depth', 'parent_id'])->first();
        if (!$menuObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '菜单不存在');
        }

        if ($menuObj->parent_id != $data['parentId']) {
            $newParentDepth = "|{$menuObj->id}";
            if ($data['parentId'] > 0) {
                $newParentDepth .= $parentObj->depth;
            } else {
                $newParentDepth .= '|';
            }
            $updateData['depth'] = $newParentDepth;
        }

        $iCnt = DB::table('sc_system_menu')->where('id', $id)->update($updateData);
        if ($iCnt) {
            $needUpdateChildId = [$id];
            $depthList = [$id => $updateData['depth'] ?? $menuObj->depth];
            while ($parentChangeId = array_pop($needUpdateChildId)) {
                $allChildList = DB::table('sc_system_menu')->where('parent_id', $parentChangeId)->get();
                foreach ($allChildList as $item) {
                    if (!array_key_exists($parentChangeId, $depthList)) {
                        continue;
                    }
                    $newDepth = '|' . $item->id . $depthList[$parentChangeId];
                    DB::table('sc_system_menu')->where('id', $item->id)->update(['depth' => $newDepth]);
                    $depthList[$item->id] = $newDepth;
                    $needUpdateChildId[] = $item->id;
                }
            }

            HandleLog()->addLog('u', $data, '编辑了菜单' . $menuObj->name);
            return ModelReturn(RETURN_SUCCESS, '修改成功');
        } else {
            return ModelReturn(RETURN_FAIL, '修改失败');
        }
    }

    /**
     * 获取菜单树状数据结构
     * @return array
     */
    public function getMenuListTree()
    {
        $allMenuList = DB::table('sc_system_menu')->whereRaw('status!=9')->orderByRaw('sort desc,create_time desc')->get();
        $menuTree = [];
        $allMenuListData = [];
        foreach ($allMenuList as $item) {
            $item = (array)$item;
            $item['childList'] = [];
            $allMenuListData[$item['id']] = $item;
        }

        foreach ($allMenuListData as &$item) {
            if ($item['parent_id'] == 0) {
                $menuTree[$item['id']] = &$item;
            } else {
                if (array_key_exists($item['parent_id'], $allMenuListData)) {
                    $allMenuListData[$item['parent_id']]['childList'][$item['id']] = &$item;
                }
            }
        }
        return $menuTree;
    }

    /**
     * 删除菜单
     * @param $data
     * @return array
     */
    public function deleteMenu($data)
    {
        $id = (int)$data['id'];
        $menuObj = DB::table('sc_system_menu')->whereRaw("id=? AND status!=9", [$id])->select(['id', 'name'])->first();
        if (!$menuObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '菜单不存在');
        }

        $menuTree = $this->getMenuListTree();
        $needDeleteId = [$id];
        while ($item = array_pop($menuTree)) {
            if (in_array($item['id'], $needDeleteId)) {
                $needDeleteId = array_merge($needDeleteId, array_keys($item['childList']));
            }
            $menuTree = array_merge($menuTree, $item['childList']);
        }
        $updateTime = time();
        try {
            DB::beginTransaction();
            $iCnt = DB::table('sc_system_menu')->whereIn('id', $needDeleteId)->update(['status' => 9, 'update_time' => $updateTime]);
            if ($iCnt) {
                Db::table('sc_system_function')->whereIn('menu_id', $needDeleteId)->update(['status' => 9, 'update_time' => $updateTime]);
                DB::table('sc_system_api')->whereIn('menu_id', $needDeleteId)->update([
                    'update_time' => time(),
                    'status' => 9
                ]);
                DB::commit();
                return ModelReturn(RETURN_SUCCESS, '删除成功');
            } else {
                DB::rollBack();
                return ModelReturn(RETURN_FAIL, '删除失败');
            }
        } catch (\Exception $e) {
            DB::rollBack();
            return ModelReturn($e->getCode(), $e->getMessage());
        }

    }

    /**
     * 获取菜单详情
     * @param $id
     * @return array
     */
    public function getMenu($id)
    {
        $menuObj = DB::table('sc_system_menu')->where('id', $id)->first();
        if (!$menuObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '菜单不存在');
        }

        $menuObj = (array)$menuObj;
        $menuObj['depthArr'] = array_reverse(explode('|', trim($menuObj['depth'], '|')));
        return ModelReturn(RETURN_SUCCESS, '获取成功', $menuObj);
    }

    /**
     * 获取菜单列表
     * @param $name
     * @param int $page
     * @param int $limit
     * @return array
     */
    public function getMenuList($name = '', $page = 1, $limit = 10)
    {
        $menuListObj = DB::table('sc_system_menu as t1')->leftJoin('sc_system_menu as t2', 't1.parent_id', '=', 't2.id')->whereRaw('t1.status!=9')->orderByRaw('t1.sort desc,t1.create_time desc')->select(['t1.*', 't2.name as parentName']);
        if ($name) {
            $menuListObj->whereRaw("t1.name like '%$name%'");
        }
        $index = ($page - 1) * $limit;
        $totalObj = clone $menuListObj;
        $total = $totalObj->count('t1.id');
        $menuListData = $menuListObj->offset($index)->limit($limit)->get();
        $menuListData = DbObjectToArr($menuListData);

        $allFunctionList = [];
        if ($menuListData) {
            $allMenuList = array_column($menuListData, 'id');
            $allFunctionList = DB::table('sc_system_function')->whereIn('menu_id', $allMenuList)->groupBy('menu_id')->pluck(Db::raw("COUNT(menu_id) as functionNum"), "menu_id");
        }

        $allFunctionList = DbObjectToArr($allFunctionList);
        array_walk($menuListData, function (&$item) use ($allFunctionList) {
            $item['menu_type_str'] = $item['menu_type'] == 1 ? 'PC' : '';
            $item['parentName'] = $item['parentName'] ?: "根";
            $item['createTimeStr'] = date("Y-m-d H:i:s", $item['create_time']);
            $item['updateTimeStr'] = date("Y-m-d H:i:s", $item['update_time']);
            $item['functionNum'] = array_key_exists($item['id'], $allFunctionList) ? $allFunctionList[$item['id']] : 0;
        });

        $data = [
            'total' => $total,
            'list' => $menuListData,
            'limit' => $limit,
            'page' => $page
        ];

        return ModelReturn(RETURN_SUCCESS, '获取成功', $data);
    }

    /**
     * 创建功能
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function addFunction($data)
    {
        $nowTime = time();
        $insertData = [
            'menu_id' => $data['id'],
            'name' => $data['functionName'],
            'key_val' => isset($data['keyVal']) ? $data['keyVal'] : "",
            'create_time' => $nowTime,
            'update_time' => $nowTime,
            'status' => 1
        ];

        $menuObj = DB::table('sc_system_menu')->where('id', $data['id'])->whereRaw("status!=9")->first();
        if (!$menuObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '菜单不存在');
        }

        $iCnt = DB::table('sc_system_function')->insertGetId($insertData);
        if ($iCnt) {
            $data['functionId'] = $iCnt;
            HandleLog()->addLog('i', $data, '创建了菜单' . $menuObj->name . '的功能:' . $data['functionName']);
            return ModelReturn(RETURN_SUCCESS, '创建成功', ['functionId' => $iCnt]);
        } else {
            return ModelReturn(RETURN_FAIL, '创建失败');
        }
    }

    /**
     * 编辑功能
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function editFunction($data)
    {
        $id = $data['functionId'];
        $nowTime = time();
        $updateData = [
            'name' => $data['functionName'],
            'key_val' => isset($data['keyVal']) ? $data['keyVal'] : "",
            'update_time' => $nowTime
        ];

        $functionObj = DB::table('sc_system_function')->where('id', $id)->whereRaw("status!=9")->first();
        if (!$functionObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '功能不存在');
        }

        $iCnt = DB::table('sc_system_function')->where('id', $id)->update($updateData);
        if ($iCnt) {
            HandleLog()->addLog('u', $data, '修改了功能' . $functionObj->name . '的信息');
            return ModelReturn(RETURN_SUCCESS, '编辑成功');
        } else {
            return ModelReturn(RETURN_FAIL, '编辑失败');
        }
    }

    /**
     * 删除功能
     * @param $id
     * @return array
     * @throws \Exception
     */
    public function deleteFunction($id)
    {
        $functionObj = DB::table('sc_system_function')->where('id', $id)->whereRaw("status!=9")->first();
        if (!$functionObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '功能不存在');
        }

        $iCnt = DB::table('sc_system_function')->where('id', $id)->update([
            'update_time' => time(),
            'status' => 9
        ]);
        if ($iCnt) {
            HandleLog()->addLog('d', ['id' => $id], '删除了功能' . $functionObj->name);
            return ModelReturn(RETURN_SUCCESS, '删除成功');
        } else {
            return ModelReturn(RETURN_FAIL, '删除失败');
        }
    }

    /**
     * 获取功能详情
     * @param $id
     * @return array
     */
    public function getFunction($id)
    {
        $functionObj = DB::table('sc_system_function')->where('id', $id)->whereRaw("status!=9")->first();
        if (!$functionObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '功能不存在');
        }

        return ModelReturn(RETURN_SUCCESS, '获取成功', DbObjectToArr($functionObj));
    }

    /**
     * 获取功能列表
     * @param $menuId
     * @param int $page
     * @param int $limit
     * @return array
     */
    public function getFunctionList($menuId, $page = 1, $limit = 10)
    {
        $index = ($page - 1) * $limit;
        $total = DB::table('sc_system_function')->where('menu_id', $menuId)->count('id');
        $functionList = DB::table('sc_system_function')->where('menu_id', $menuId)->whereRaw('status!=9')->orderBy('id')->offset($index)->limit($limit)->get();
        $functionList = DbObjectToArr($functionList);
        $data = [
            'total' => $total,
            'list' => $functionList,
            'limit' => $limit,
            'page' => $page
        ];

        return ModelReturn(RETURN_SUCCESS, '获取成功', $data);
    }

    /**
     * 添加权限路由
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function addApiRoute($data)
    {
        $nowTime = time();
        $insertData = [
            'menu_id' => $data['id'],
            'name' => $data['apiRouteName'],
            'url' => $data['apiRouteUrl'],
            'description' => isset($data['description']) ? $data['description'] : "",
            'create_time' => $nowTime,
            'update_time' => $nowTime,
            'status' => 1
        ];

        $menuObj = DB::table('sc_system_menu')->where('id', $data['id'])->whereRaw("status!=9")->first();
        if (!$menuObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '菜单不存在');
        }

        $iCnt = DB::table('sc_system_api')->insertGetId($insertData);
        if ($iCnt) {
            $data['id'] = $iCnt;
            HandleLog()->addLog('i', $data, '创建了菜单' . $menuObj->name . '的权限:' . $data['apiRouteName']);
            return ModelReturn(RETURN_SUCCESS, '创建成功', ['routeId'=>$iCnt]);
        } else {
            return ModelReturn(RETURN_FAIL, '创建失败');
        }
    }

    /**
     * 编辑权限路由
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function editApiRoute($data)
    {
        $id = $data['apiRouteId'];
        $nowTime = time();
        $updateData = [
            'name' => $data['apiRouteName'],
            'description' => isset($data['description']) ? $data['description'] : "",
            'url' => $data['apiRouteUrl'],
            'update_time' => $nowTime
        ];

        $apiObj = DB::table('sc_system_api')->where('id', $id)->whereRaw("status!=9")->first();
        if (!$apiObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '功能不存在');
        }

        $iCnt = DB::table('sc_system_api')->where('id', $id)->update($updateData);
        if ($iCnt) {
            HandleLog()->addLog('u', $data, '修改了功能' . $apiObj->name . '的信息');
            return ModelReturn(RETURN_SUCCESS, '编辑成功');
        } else {
            return ModelReturn(RETURN_FAIL, '编辑失败');
        }
    }

    /**
     * 删除权限路由
     * @param $id
     * @return array
     * @throws \Exception
     */
    public function deleteApiRoute($id)
    {
        $apiObj = DB::table('sc_system_api')->where('id', $id)->whereRaw("status!=9")->first();
        if (!$apiObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, 'API对象不存在');
        }

        $iCnt = DB::table('sc_system_api')->where('id', $id)->update([
            'update_time' => time(),
            'status' => 9
        ]);
        if ($iCnt) {
            HandleLog()->addLog('d', ['id' => $id], '删除了API' . $apiObj->name);
            return ModelReturn(RETURN_SUCCESS, '删除成功');
        } else {
            return ModelReturn(RETURN_FAIL, '删除失败');
        }
    }

    /**
     * 获取权限路由
     * @param $id
     * @return array
     */
    public function getApiRoute($id)
    {
        $apiObj = DB::table('sc_system_api')->where('id', $id)->whereRaw("status!=9")->first();
        if (!$apiObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, 'API对象不存在');
        }
        $apiObj = DbObjectToArr($apiObj);
        return ModelReturn(RETURN_SUCCESS, '获取成功', $apiObj);
    }

    /**
     * 获取权限路由列表
     * @param $menuId
     * @param int $page
     * @param int $limit
     * @return array
     * @throws \think\DB\exception\DataNotFoundException
     * @throws \think\DB\exception\ModelNotFoundException
     * @throws \think\exception\DBException
     */
    public function getApiRouteList($menuId, $page = 1, $limit = 10)
    {
        $index = ($page - 1) * $limit;
        $total = DB::table('sc_system_api')->where('menu_id', $menuId)->count('id');
        $functionList = DB::table('sc_system_api')->where('menu_id', $menuId)->whereRaw('status!=9')->orderBy('id')->offset($index)->limit($limit)->get();
        $functionList = DbObjectToArr($functionList);
        $data = [
            'total' => $total,
            'list' => $functionList,
            'limit' => $limit,
            'page' => $page
        ];
        return ModelReturn(RETURN_SUCCESS, '获取成功', $data);
    }
}
